package com.ton.common.controller.order;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.hai.admin.table.vo.Result;
import com.kypj.frame.db.Pager;
import com.ton.common.controller.order.req.LinkWalletReq;
import com.ton.common.controller.order.req.PayOrderAddReq;
import com.ton.common.controller.order.req.QueryOrderReq;
import com.ton.common.controller.order.resp.PayOrderPollResp;
import com.ton.common.controller.order.resp.PayOrderQueryResp;
import com.ton.common.controller.order.resp.PayOrderResp;
import com.ton.common.controller.order.resp.QueryOrderResp;
import com.ton.common.controller.task.PayOrderPayingTask;
import com.ton.common.controller.task.PayOrderTrans;
import com.ton.common.convertor.OrderConvertor;
import com.ton.common.entity.TonPayOrder;
import com.ton.common.entity.TronAccount;
import com.ton.common.service.PayOrderService;
import com.ton.context.RedisContext;
import com.ton.system.dto.R;
import com.ton.utils.http.RestTemplateUtils;
import com.ton.utils.quartz.QueueUtils;
import com.ton.utils.tron.http.TonscanAPI;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.net.InetAddress;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
 * 订单控制器
 */
@RestController
@RequestMapping("/order")
@Api(value = "订单控制器", tags = "订单控制器")
@Slf4j
public class PayOrderController {


    @Autowired
    private RedisContext redisContext;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private Scheduler scheduler; //Quartz定时任务调度

    @Autowired
    private PayOrderService payOrderService;

    @Autowired
    private QueueUtils queueUtils;



    //模拟订单
    public void addTask() {
        TonPayOrder tonPayOrder = new TonPayOrder();
        tonPayOrder.setCreateTime(new Date());
        tonPayOrder.setId(123456789L); //订单ID
        tonPayOrder.setStatus(0);
        tonPayOrder.setAmount(2L);
        tonPayOrder.setCoinType(0); //货币类型 0=TRX 1=TRC20(USDT)
        tonPayOrder.setRemark("测试");
        tonPayOrder.setAppName("测试订单");
        tonPayOrder.setCallbackUrl("https://www.baidu.com");
        tonPayOrder.setTargetAmount(4L);
        tonPayOrder.setPrivateKey("fcafe9ea85dd055d942120dd2579420bc76003dcc4e7e4437137afe7f826fe19"); //模拟账户的私钥

        PayOrderTrans payOrderTrans = PayOrderTrans.createFrom(tonPayOrder);
        PayOrderPayingTask.addOrder(payOrderTrans);
//         orderMap.put(payOrderTrans.getOrderId(), payOrderTrans);
    }

    @PostMapping("/create")
    @ApiOperation(value = "创建订单", notes = "创建订单")
    @Transactional
    public Result createOrderQuartz(@RequestBody PayOrderAddReq payOrderAddReq) throws InterruptedException {
        Optional.ofNullable(payOrderAddReq.getCoinType()).orElseThrow(() -> new IllegalArgumentException("创建订单的必要参数 coinType 不能为空"));
        Optional.ofNullable(payOrderAddReq.getMerchantOrderId()).orElseThrow(() -> new IllegalArgumentException("创建订单的必要参数商家订单号 merchant_order_id 不能为空"));

        //对象转换
        TonPayOrder tonPayOrder = OrderConvertor.MAPPER.ob2en(payOrderAddReq);
        tonPayOrder.setStatus(0); //设置状态为订单未完成
        tonPayOrder.setCreateTime(new Date()); //设置当前时间
        tonPayOrder.setId(IdUtil.getSnowflake(1, 1).nextId());

        TonPayOrder payOrderMerchant = payOrderService.getPayOrderMerchantId(payOrderAddReq.getMerchantOrderId());
        if(Objects.nonNull(payOrderMerchant)){
            throw new RuntimeException("已存在该订单！请勿重复下单");
        }

        //记录订单信息
        payOrderService.save(tonPayOrder);

        //转换返回对象
        PayOrderResp payOrderResp = OrderConvertor.MAPPER.en2resp(tonPayOrder);
        payOrderResp.setOrderId(tonPayOrder.getId());

        //执行订单后置处理器
        //orderPostProcessor(payOrder); //redis存入
        //PayOrderTrans from = PayOrderTrans.createFrom(tonPayOrder);
        //PayOrderPayingTask.addOrder(from);
        // createTask(payOrder);

        String ip = "127.0.0.1";
        try {
            ip = InetAddress.getLocalHost().getHostAddress();
        } catch (Exception e) {
            log.error("ip获取失败");
        }
        String builder = "http://localhost:3000/" +
                payOrderResp.getOrderId();
        payOrderResp.setPayUrl(builder);

        String jsonStr = JSONUtil.toJsonStr(payOrderResp);
        return new Result().setData(JSONUtil.toBean(jsonStr, Map.class));
    }

    @PostMapping("/link/wallet")
    @ApiOperation(value="连接钱包",notes = "连接钱包")
    public Result linkWaller(@RequestBody LinkWalletReq linkWalletReq){
      Optional.ofNullable(linkWalletReq.getOrderId()).orElseThrow(()->new IllegalArgumentException("必要参数订单ID不能为空"));
      Optional.ofNullable(linkWalletReq.getAddress()).orElseThrow(()->new IllegalArgumentException("必要参数钱包地址不能为空"));
      Optional.ofNullable(linkWalletReq.getHash()).orElseThrow(()->new IllegalArgumentException("必要参数账户Hash不能为空"));

      TonPayOrder payOrderById = payOrderService.getPayOrderById(linkWalletReq.getOrderId());
      Optional.ofNullable(payOrderById).orElseThrow(()->new IllegalArgumentException("订单异常!已失效"));
      payOrderById.setFromAddress(linkWalletReq.getAddress()); //设置出账账户

      payOrderService.updatePayOrder(payOrderById);
      return new Result().setSuccessMsg("更新成功!");
    }

    /**
     * 充值完成后回调 校验
     * @param code 订单id
     * @return
     */
    @GetMapping("/verify")
    @ApiOperation(value = "校验订单", notes = "校验订单")
    public Result verifyOrder(@RequestParam("code") Long code) {
        //过滤参数
        Optional.ofNullable(code).orElseThrow(() -> new IllegalArgumentException("缺少必要参数！code"));
        if (String.valueOf(code).length() <= 5) {
            throw new IllegalArgumentException("参数异常!code");
        }

        //第一步：先去数据库查询数据
        TonPayOrder tonPayOrder = payOrderService.getPayOrderById(code);
        Optional.ofNullable(tonPayOrder).orElseThrow(() -> new RuntimeException("订单已失效!"));

        Integer targetCount = 0;

        //第二步：进行API交易查询
        //return getTransactionInfo(tonPayOrder.getFromAddress(),String.valueOf(code),tonPayOrder,targetCount);

        //创建一个Callable 的任务 丢入队列 在开始操作之前也需要查询

        getFutureTask(tonPayOrder.getFromAddress(), String.valueOf(code), tonPayOrder, targetCount);
        return new Result().setErrorMsg("交易正在确认...");
    }

    public void getFutureTask(String address, String orderId, TonPayOrder tonPayOrder, Integer targetCount){
         Callable<Object> callable = () -> {
            if(Objects.isNull(tonPayOrder.getFromAddress())){
                System.out.println("查询地址不能为空");
                return null;
            }
            String json = TonscanAPI.getEvents(tonPayOrder.getFromAddress());

            if (json.indexOf(String.valueOf(orderId)) > 1) {
                //交易成功！！
                //更新数据库状态
                tonPayOrder.setStatus(1);//已完成
                payOrderService.updatePayOrder(tonPayOrder);
                System.out.println("交易成功！！");
                transferOk(tonPayOrder);
                Result result = new Result().setSuccessMsg("交易成功!");
                return result;
            }
            System.out.println("交易未知！");
            Result result = new Result().setErrorMsg("交易未知!");
            return result;
        };
        FutureTask<Object> submit = queueUtils.submit(callable);
        try {
            Result result = (Result) submit.get();
            if(result.getCode()!=200){
                targetCount++;
                if(targetCount==30){
                    tonPayOrder.setStatus(0); //未完成
                    payOrderService.updateFailStatus(tonPayOrder);
                    return;
                }
                //不等于60 重新调用
                getFutureTask(address ,orderId ,tonPayOrder ,targetCount);
            }else{
                //System.out.println("交易成功啦！！！！！");
            }
        }catch (Exception e){
            log.error("任务执行失败!!!");
        }
    }

    //回调链接
    public void transferOk(TonPayOrder order) {
        if (order.getCallbackUrl().contains("http")) {
            HashMap<String, Object> params = new HashMap<>();
            params.put("orderId", order.getId()); // 订单号
            params.put("merchantOrderId", order.getMerchantOrderId()); //商家订单号
            params.put("amount", order.getAmount()); //支付金额
            params.put("appId", order.getAppId()); //appid
            params.put("bankMsg", ""); //信息
            params.put("time", order.getCreateTime()); //订单创建时间
            params.put("coinType", order.getCoinType()); //货币类型
            params.put("remark", order.getRemark()); //备注
            params.put("status", 2); //成功
            String doPost = RestTemplateUtils.doPost(order.getCallbackUrl(), new HashMap<>(), params);
            log.info("完成支付回调！！");
        }
    }

    @GetMapping("/transaction/status")
    @ApiOperation(value = "交易状态查询", notes = "交易状态查询")
    public Result queryTransactionStatus(@RequestParam("code") Long code){
        //过滤参数
        Optional.ofNullable(code).orElseThrow(() -> new IllegalArgumentException("缺少必要参数！code"));
        if (String.valueOf(code).length() <= 5) {
            throw new IllegalArgumentException("参数异常!code");
        }

        //第一步：先去数据库查询数据
        TonPayOrder tonPayOrder = payOrderService.getPayOrderById(code);
        Optional.ofNullable(tonPayOrder).orElseThrow(() -> new RuntimeException("订单已失效!"));
        if(tonPayOrder.getStatus()==1){
            //已完成
            return new Result().setSuccessMsg("Successful transaction!");
        }
        String json ="";
        try {
            json = TonscanAPI.getEvents(tonPayOrder.getFromAddress());
        }catch (Exception e){
            log.error("Failed to obtain blockchain transaction information!");
            return new Result().setErrorMsg("Failed to obtain blockchain transaction information!");
        }
         if (json.indexOf(String.valueOf(code)) > 1) {
                //交易成功！！
                //更新数据库状态
                tonPayOrder.setStatus(1);//已完成
                payOrderService.updatePayOrder(tonPayOrder);
                System.out.println("Successful transaction!！！");
                Result result = new Result().setSuccessMsg("Successful transaction!");
                return result;
         }
         return new Result().setErrorMsg("Uncompleted transaction!");
    }


    /**
     * 查询交易记录
     * @param address 查询的地址
     * @param orderId 订单id
     * @param tonPayOrder 数据库查询出来的订单对象
     * @param targetCount 轮询目标次数
     * @return Result 返回结果
     * @throws InterruptedException 抛出中断异常
     */
    public Result getTransactionInfo(String address,String orderId,TonPayOrder tonPayOrder,Integer targetCount)  {
        try {
            Thread.sleep(3000); //先延迟3秒查询 (交易后不也能立即收到结果,需要延迟一定时间来查询)
        }catch (Exception e){
            log.error("睡眠失败！！");
            return new Result().setErrorMsg("交易失败");
        }
        System.out.println("次数++:"+targetCount);
        String json = TonscanAPI.getEvents(address);
        if (json.indexOf(orderId) > 1) {
            //交易成功！！
            //更新数据库状态
            tonPayOrder.setStatus(1);//已完成
            payOrderService.updatePayOrder(tonPayOrder);
            System.out.println("交易成功！！");
            return new Result().setSuccessMsg("交易成功");
        }
        // 如果次数小于2次则重复查询 2 * 10 * 3
        if(targetCount==60){
            tonPayOrder.setStatus(0); //未完成
            payOrderService.updateFailStatus(tonPayOrder);
            System.out.println("交易失败！！");
            return new Result().setErrorMsg("交易失败");
        }
        targetCount++;
        System.out.println("轮询！！");
        Result info = getTransactionInfo(address, orderId, tonPayOrder, targetCount);
        return info;

    }


    @GetMapping("/query")
    @ApiOperation(value = "查询订单", notes = "查询订单")
    public R<?> orderQueryById(@RequestParam("number") Long number) {
        //数据库查询
        TonPayOrder tonPayOrderById = payOrderService.getPayOrderById(number);
        if (Objects.isNull(tonPayOrderById)) {
            throw new IllegalArgumentException("订单异常！！！");
        }
        //转换返回对象
        PayOrderQueryResp resp = OrderConvertor.MAPPER.en2QueryResp(tonPayOrderById);
        Long expired = PayOrderPayingTask.getExpired(number);
        resp.setExpire(expired);
        resp.setOrderId(tonPayOrderById.getId());
        return R.ok(resp);
    }


    @GetMapping("/poll/query")
    @ApiOperation(value = "轮询查询订单", notes = "轮询查询订单")
    public R<?> orderPollQueryById(@RequestParam("orderId") Long orderId, @RequestParam("address") String address) {
        TonPayOrder order = PayOrderPayingTask.getOrderById(orderId); //去缓存里面找 如果缓存里面有就不用去数据库里面找了
        //能找出来就说明订单一定没有完成
        if (Objects.nonNull(order)) {
            //能找出来
            Long expired = PayOrderPayingTask.getExpired(orderId);
            PayOrderPollResp pollResp = new PayOrderPollResp(String.valueOf(orderId), address, expired, 0);
            return R.ok(pollResp);
        }

        //缓存没有数据 说明已失效 或者是 已完成
        //查询数据库
        TonPayOrder tonPayOrder = payOrderService.getPayOrderById(orderId);

        //表示已完成订单
        if (tonPayOrder.getStatus() == 1) {
            //交易成功
            PayOrderPollResp pollResp = new PayOrderPollResp(String.valueOf(orderId), address, 500L, 1);
            return R.ok(pollResp);
        }

        //-1 表示已超时订单
        PayOrderPollResp pollResp = new PayOrderPollResp(String.valueOf(orderId), address, -1L, -1);
        return R.ok(pollResp);
    }


    @GetMapping("/query/list")
    @ApiOperation(value = "分页查询订单", notes = "分页查询订单")
    public Result queryOrder(QueryOrderReq queryOrderReq, Pager pager) {
        List<TonPayOrder> list = payOrderService.queryList(queryOrderReq, pager);
        List<QueryOrderResp> resps = OrderConvertor.MAPPER.ob2respArr(list);
        return new Result().addData("list", resps)
                .addData("pager", pager);
    }
}
